package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumAttributeValueMapper;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.cache.GuiGuCache;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private AlbumAttributeValueMapper albumAttributeValueMapper;

    @Autowired
    private AlbumStatMapper albumStatMapper;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private TrackStatMapper trackStatMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void trackStatUpdate(TrackStatMqVo trackStatMqVo) {
        //  执行update 语句; update track_stat set stat_num = stat_num + 1 where stat_type = ? and track_id = ?  and is_deleted = 0;
        trackStatMapper.updateTrackStat(trackStatMqVo.getTrackId(), trackStatMqVo.getCount(), trackStatMqVo.getStatType());
        //  更新专辑的播放量!
        if (SystemConstant.TRACK_STAT_PLAY.equals(trackStatMqVo.getStatType())) {
            //  调用mapper层方法 update album_stat set stat_num = stat_num + 1 where album_id = ? and stat_type = ? and is_deleted = 0;
            albumInfoMapper.updateAlbumStat(trackStatMqVo.getAlbumId(), SystemConstant.ALBUM_STAT_PLAY, trackStatMqVo.getCount());
        }
    }

    @Override
    @GuiGuCache(prefix = "albumStatVo:")
    public AlbumStatVo getAlbumStatVo(Long albumId) {
        //  调用服务层方法
        return albumInfoMapper.selectAlbumStatVo(albumId);
    }

    @Override
    public List<AlbumAttributeValue> findAlbumAttributeValue(Long albumId) {
        return albumAttributeValueMapper.selectList(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId));
    }

    @Override
    public List<AlbumInfo> findUserAllAlbumList(Long userId) {
        //  select id,album_title from album_info where user_id = 1 and is_deleted = 0 order by id desc limit 100;
        return albumInfoMapper.selectList(new LambdaQueryWrapper<AlbumInfo>().eq(AlbumInfo::getUserId, userId).select(AlbumInfo::getAlbumTitle, AlbumInfo::getId).orderByDesc(AlbumInfo::getId).last(" limit 50 "));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAlbumInfo(Long albumId, AlbumInfoVo albumInfoVo) {
        //  根据专辑Id 修改数据
        //  del(key);
        //  创建专辑实体类
        AlbumInfo albumInfo = new AlbumInfo();
        //  给专辑赋值;
        albumInfo.setId(albumId);
        //  属性拷贝：
        BeanUtils.copyProperties(albumInfoVo, albumInfo);
        albumInfoMapper.updateById(albumInfo);

        //  删除原有的数据，再新增数据
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId));
        //  先获取到前端传递的专辑对应的属性与属性值集合
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        if (!CollectionUtils.isEmpty(albumAttributeValueVoList)) {
            for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
                //  创建一个对象
                AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                //  赋值：
                BeanUtils.copyProperties(albumAttributeValueVo, albumAttributeValue);
                albumAttributeValue.setAlbumId(albumId);
                //  保存数据
                albumAttributeValueMapper.insert(albumAttributeValue);
            }
        }
        // 睡眠.
        // del(key);
        //  判断
        if ("1".equals(albumInfoVo.getIsOpen())) {
            //  上架
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumId);
        } else {
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_LOWER, albumId);
        }

    }

    @Override
    @GuiGuCache(prefix = RedisConstant.ALBUM_INFO_PREFIX)
    public AlbumInfo getAlbumInfo(Long albumId) {
        //  return getAlbumInfoByRedisson(albumId);
        return getAlbumInfoDB(albumId);
    }

    private AlbumInfo getAlbumInfoByRedisson(Long albumId) {
        //  查询缓存数据；String Hash;
        String key = RedisConstant.ALBUM_INFO_PREFIX + albumId;
        //  根据key来获取数据
        try {
            AlbumInfo albumInfo = (AlbumInfo) this.redisTemplate.opsForValue().get(key);
            if (null == albumInfo) {
                //  说明缓存中没有数据，使用 redisson 上锁！
                //  声明一个锁的key
                String locKey = RedisConstant.ALBUM_LOCK_SUFFIX + albumId;
                //  获取到lock对象
                RLock lock = redissonClient.getLock(locKey);
                //  上锁
                lock.lock();
                try {
                    //  可能有人将数据存储到缓存
                    albumInfo = (AlbumInfo) this.redisTemplate.opsForValue().get(key);
                    //  判断缓存中是否有数据
                    if (null != albumInfo){
                        //  返回缓存数据
                        return albumInfo;
                    }
                    //  查询数据库. 考虑是否会出现击穿！
                    albumInfo = getAlbumInfoDB(albumId);
                    //  判断一下
                    if (null == albumInfo) {
                        //  将空对象存储到缓存
                        this.redisTemplate.opsForValue().set(key, new AlbumInfo(), RedisConstant.ALBUM_TEMPORARY_TIMEOUT, TimeUnit.SECONDS);
                        //  默认返回空对象
                        return new AlbumInfo();
                    }
                    //  将查询到的数据存储到缓存！
                    this.redisTemplate.opsForValue().set(key, albumInfo, RedisConstant.ALBUM_TIMEOUT, TimeUnit.SECONDS);
                    //  返回数据
                    return albumInfo;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    //  解锁
                    lock.unlock();
                }
            }else {
                //  返回数据
                return albumInfo;
            }
        } catch (RuntimeException e) {
            log.info("出现异常"+e.getMessage());
        }
        //  数据库兜底！
        return getAlbumInfoDB(albumId);
    }

    private AlbumInfo getAlbumInfoDB(Long albumId) {
        //  获取专辑对象
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        //  根据专辑id 获取属性与属性值集合列表
        if (null != albumInfo) {
            albumInfo.setAlbumAttributeValueVoList(this.albumAttributeValueMapper.selectList(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId)));
        }
        //  返回专辑对象
        return albumInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeAlbumInfo(Long albumId) {
        //album_info;
        //album_attribute_value;
        //album_stat;
        //  删除有两种方式：一种方式是：物理删除 一种方式：逻辑删除！
        albumInfoMapper.deleteById(albumId);
        //  根据专辑Id 删除 album_attribute_value 数据
        //  delete from album_attribute_value where album_id = ?;  物理
        //  update album_attribute_value set is_deleted = 1 where album_id = ? 逻辑删除！
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId));
        albumStatMapper.delete(new LambdaQueryWrapper<AlbumStat>().eq(AlbumStat::getAlbumId, albumId));

        //  发送消息
        rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_LOWER, albumId);
    }

    @Override
    public IPage<AlbumListVo> findUserAlbumPage(Page<AlbumListVo> albumListVoPage, AlbumInfoQuery albumInfoQuery) {
        //  查询数据：专辑名称 ,专辑统计
        return albumInfoMapper.selectUserAlbumPage(albumListVoPage, albumInfoQuery);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo) {
		/*
		album_info;
		album_attribute_value;
		album_stat;
		 */
        //	创建一个专辑对象
        AlbumInfo albumInfo = new AlbumInfo();
        //	属性拷贝
        BeanUtils.copyProperties(albumInfoVo, albumInfo);
        //	获取用户Id
        Long userId = AuthContextHolder.getUserId() == null ? 1L : AuthContextHolder.getUserId();
        albumInfo.setUserId(userId);
        //	免费试听集数 ；vip付费或 付费才会设置这个属性数据
        if (!albumInfoVo.getPayType().equals(SystemConstant.ALBUM_PAY_TYPE_FREE)) {
            //	设置前集免费
            albumInfo.setTracksForFree(5);
        }
        albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
        albumInfoMapper.insert(albumInfo);

        //	album_attribute_value
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        if (!CollectionUtils.isEmpty(albumAttributeValueVoList)) {
            for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
                //	创建实体类
                AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                //	赋值数据
                BeanUtils.copyProperties(albumAttributeValueVo, albumAttributeValue);
                //	什么有专辑Id @TableId(type = IdType.AUTO) 表示数据插入之后会自动获取到当前表的主键Id
                albumAttributeValue.setAlbumId(albumInfo.getId());
                //	执行5次insert 语句. 后续可以优化一条insert 语句 insert into
                albumAttributeValueMapper.insert(albumAttributeValue);
            }
        }
        //	album_stat
        this.saveAllbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_PLAY);
        this.saveAllbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_SUBSCRIBE);
        this.saveAllbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_BROWSE);
        this.saveAllbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_COMMENT);
        //  判断
        if ("1".equals(albumInfoVo.getIsOpen())) {
            //  上架
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumInfo.getId());
        } else {
            //  下架
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_LOWER, albumInfo.getId());
        }
    }

    /**
     * 保存专辑统计数据
     *
     * @param albumId
     * @param statPlay
     */
    private void saveAllbumStat(Long albumId, String statPlay) {
        //	创建统计对象
        AlbumStat albumStat = new AlbumStat();

//        int i = 1 / 0;
        //	赋值：
        albumStat.setAlbumId(albumId);
        albumStat.setStatType(statPlay);
        albumStat.setStatNum(0);
        albumStatMapper.insert(albumStat);
    }
}
